/***************************************************************************
                          main.c  -  Part of gltris
                             -------------------
    begin                : March 2001
    copyright            : (C) 2001 by David Delbecq (Alias Tchize)
    email                : david.delbecq@usa.net
 ***************************************************************************/
/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

/****************************************************************************
* main program entrypoint. Handles openGL startup, idle loop, game creation,*
* menu intervention.                                                        *
****************************************************************************/
#include "os_depend.h"
#include <GL/gl.h>
#include <GL/glut.h>
#include <GL/glu.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include "drawing.h"
#include "game.h"
#include "tgaload.h"
#include "textures.h"
#include "menu.h"

#define idletimeout 5



/* __FOR INFORMATION (RIPPED FROM menu.h)__
typedef struct
        {
        int entrytype;
        char* text;
        void * data; //an integer for the key or a pointer to a string or a pointer to a submenulist etc. depend on entrytype
        int isusable;
        }Tmenuentry;

typedef struct structmenulist
        {
        int activeitem;
        int itemscount;
        struct structmenulist* previousmenu;  // When pressing the escape key
        Tmenuentry* menuentries;
        }Tmenulist, *menuobj;
*/


int RequiresFullScreen; //是否全屏


menuobj SysMenu=NULL;//菜单

menuobj getPlayerMenu (playerobj po)
        {
        menuobj playermenu;
        Tmenuentry* playerinfo;
        playermenu=malloc (sizeof (Tmenulist));
        if (playermenu==NULL) return NULL;
        playerinfo=malloc (sizeof (Tmenuentry)*10);
        if (playerinfo==NULL)
                {
                free (playermenu);
                return NULL;
                }
        playermenu->menuentries=playerinfo;
        playermenu->itemscount=10;//菜单项数目
        playermenu->activeitem=0;//代表哪个项是激活状态
        playerinfo[0].entrytype=MENU_TEXT;//代表此项的类型
        playerinfo[0].text= "Name: ";//显示的内容
        playerinfo[0].data=&po->Name;//存储的数据，依赖此项的类型
        playerinfo[0].isusable=true;//是否可用,如果不可用的话，通过键盘就不会使此项出现选中状态
        playerinfo[1].entrytype=MENU_TITLE;
        playerinfo[1].text="  Keybindings";
        playerinfo[1].data=NULL;
        playerinfo[1].isusable=false;
        playerinfo[2].entrytype=MENU_KEY;
        playerinfo[2].text="Left: ";
        playerinfo[2].data=&Pldraw[po->tag]->keyleft;
        playerinfo[2].isusable=true;
        playerinfo[3].entrytype=MENU_KEY;
        playerinfo[3].text="Right: ";
        playerinfo[3].data=&Pldraw[po->tag]->keyright;
        playerinfo[3].isusable=true;
        playerinfo[4].entrytype=MENU_KEY;
        playerinfo[4].text="Drop piece: ";
        playerinfo[4].data=&Pldraw[po->tag]->keydrop;
        playerinfo[4].isusable=true;
        playerinfo[5].entrytype=MENU_KEY;
        playerinfo[5].text="Turn clockwise: ";
        playerinfo[5].data=&Pldraw[po->tag]->keyturnclockwise;
        playerinfo[5].isusable=true;
        playerinfo[6].entrytype=MENU_KEY;
        playerinfo[6].text="Turn counter clockwise: ";
        playerinfo[6].data=&Pldraw[po->tag]->keyturncounterclockwise;
        playerinfo[6].isusable=true;
        playerinfo[7].entrytype=MENU_KEY;
        playerinfo[7].text="Previous bonus: ";
        playerinfo[7].data=&Pldraw[po->tag]->keyprevbonus;
        playerinfo[7].isusable=true;
        playerinfo[8].entrytype=MENU_KEY;
        playerinfo[8].text="Next Bonus: ";
        playerinfo[8].data=&Pldraw[po->tag]->keynextbonus;
        playerinfo[8].isusable=true;
        playerinfo[9].entrytype=MENU_KEY;
        playerinfo[9].text="Use bonus: ";
        playerinfo[9].data=&Pldraw[po->tag]->keyusebonus;
        playerinfo[9].isusable=true;
        return playermenu;
        }


/* 显示系统菜单*/
menuobj getSystemMenu ()
        {
        static Tmenulist menu;/*主菜单*/
        static Tmenuentry mainmenu[5];/*主菜单的子菜单项*/
        static menuobj player1;/*选手一的配置菜单*/
        static menuobj player2;/*选手二的配置菜单*/
        menu.activeitem=0;//使菜单一选中状态
        menu.itemscount=5;//5个子菜单项
        menu.menuentries=mainmenu;//子菜单项对象
        player1=getPlayerMenu (po);//创建选手一的配置菜单
        player2=getPlayerMenu (po2);//创建选手二的配置菜单
        player1->previousmenu=&menu;//设置它们的前一级菜单
        player2->previousmenu=&menu;
        mainmenu[0].entrytype=MENU_LINK;//菜单项的属性
        mainmenu[0].text="Player 1 setup";//菜单项显示内容
        mainmenu[0].data=player1;//根据期间项属性，指向字符串或是菜单项或是其它内容
        mainmenu[0].isusable=true;//是否可用
        mainmenu[1].entrytype=MENU_LINK;
        mainmenu[1].text="Player 2 setup";
        mainmenu[1].data=player2;
        mainmenu[1].isusable=true;
        mainmenu[2].entrytype=MENU_BOOLEAN;
        mainmenu[2].text="FullScreen mode";
        mainmenu[2].data=&RequiresFullScreen;
        RequiresFullScreen=isFullScreen;
        mainmenu[2].isusable=true;
        mainmenu[3].entrytype=MENU_RETURNSTATUS;
        mainmenu[3].text="To the game";
        mainmenu[3].data=0;
        mainmenu[3].isusable=true;
        mainmenu[4].entrytype=MENU_RETURNSTATUS;
        mainmenu[4].text="Quit";
        mainmenu[4].data=(void*)0xdeadbeef;
        mainmenu[4].isusable=true;
        SysMenu=&menu;
        return &menu;
        }

void backmenu (int returnvalue);

int idletimer=idletimeout;
int pause=(0==1);

GLfloat lightposition[4]={0,2,10,0};//灯光的位置
GLfloat direction[4]={0.0,0.0,-1.0};//灯光的方向

void init(void)
        {
        int i;
        GLint maxtexarb;
        srand (clock());//Initialize random number generator
        LoadTextures();
        glEnable (GL_LIGHTING);
        glEnable (GL_LIGHT0);
        glLightfv (GL_LIGHT0,GL_POSITION,lightposition);
        glLightfv (GL_LIGHT0,GL_SPOT_DIRECTION,direction);
        glShadeModel(GL_SMOOTH);
        GraphicalInit ();
        glClearColor (0.0,0.0,0.0,1.0);
        glClearDepth(1.0f);
        glClearStencil (0);//指定了glClear 函数清理目标缓冲区时使用的重置值.
        glEnable(GL_DEPTH_TEST);
        glDepthFunc(GL_LEQUAL);
        glEnable ( GL_COLOR_MATERIAL );
        glEnable (GL_TEXTURE_2D);
        glEnable (GL_STENCIL_TEST);
        po=CreateGame ("Player 1");
        po->tag=0;
        Pldraw[po->tag]=malloc (sizeof (TPlayerDrawable));
        Pldraw[po->tag]->Thunder=NULL;
        Pldraw[po->tag]->Thunderized=GetStubSpark();
        Pldraw[po->tag]->Thunderizedcount=0;
        for (i=0;i<6;i++)
                Pldraw[po->tag]->flares[i]=createlight (0.0,0.55,0.55, 1.0,1.0,1.0, 0.75);
        Pldraw[po->tag]->keyleft=(int)'q'|KEY_NORMAL_MASK;
        Pldraw[po->tag]->keyright=(int)'d'|KEY_NORMAL_MASK;
        Pldraw[po->tag]->keyturnclockwise=(int)'z'|KEY_NORMAL_MASK;
        Pldraw[po->tag]->keyturncounterclockwise=(int)'s'|KEY_NORMAL_MASK;
        Pldraw[po->tag]->keynextbonus=(int)'e'|KEY_NORMAL_MASK;
        Pldraw[po->tag]->keyprevbonus=(int)'a'|KEY_NORMAL_MASK;
        Pldraw[po->tag]->keyusebonus=(int)9|KEY_NORMAL_MASK; /*Tab Key*/
        Pldraw[po->tag]->keydrop=(int)' '|KEY_NORMAL_MASK;
        po2=CreateGame ("Player 2");
        po2->tag=1;
        Pldraw[po2->tag]=malloc (sizeof (TPlayerDrawable));
        Pldraw[po2->tag]->old_animstep=0;
        Pldraw[po2->tag]->spotx_alpha=0.0;
        Pldraw[po2->tag]->spoty_alpha=0.0;
        Pldraw[po2->tag]->Thunder=NULL;
        Pldraw[po2->tag]->Thunderized=GetStubSpark();
        Pldraw[po2->tag]->Thunderizedcount=0;
        for (i=0;i<6;i++)
                Pldraw[po2->tag]->flares[i]=createlight (0.0,0.55,0.55, 1.0,1.0,1.0, 0.75);
        Pldraw[po2->tag]->keyleft=(int)'4'|KEY_NORMAL_MASK;
        Pldraw[po2->tag]->keyright=(int)'6'|KEY_NORMAL_MASK;
        Pldraw[po2->tag]->keyturnclockwise=(int)'8'|KEY_NORMAL_MASK;
        Pldraw[po2->tag]->keyturncounterclockwise=(int)'2'|KEY_NORMAL_MASK;
        Pldraw[po2->tag]->keynextbonus=(int)'9'|KEY_NORMAL_MASK;
        Pldraw[po2->tag]->keyprevbonus=(int)'7'|KEY_NORMAL_MASK;
        Pldraw[po2->tag]->keyusebonus=(int)'5'|KEY_NORMAL_MASK;
        Pldraw[po2->tag]->keydrop=(int)13|KEY_NORMAL_MASK;      /*Enter Key*/
        setOpponents (po,&po2,1);
        setOpponents (po2,&po,1);
        StartGame (po);
        StartGame (po2);
        pauseGame (po);
        pauseGame (po2);
        printf ("Your implementation support the following extensions:\n[%s]\n",glGetString (GL_EXTENSIONS));
#ifdef GL_MAX_TEXTURE_UNITS_ARB
        glGetIntegerv (GL_MAX_TEXTURE_UNITS_ARB,&maxtexarb);
        printf ("Max number of multi-textures allowed: %d\n",maxtexarb);
        if (maxtexarb<2) printf ("\t\tThis is not enough!!\n");
#endif

        }
void reshape (int w, int h)
        {
        if (h==0) h=1;
        windoww=w;
        windowh=h;
        #ifdef DEBUG
        printf ("Got %i x %i window.\n",w,h);
        #endif
        glutPostRedisplay();
        }
void usekey (int key)
        {
                if (key==Pldraw[po2->tag]->keyleft)
                        moveleft(po2->Map,&po2->dropped);
                        else
                if (key==Pldraw[po2->tag]->keyright)
                        moveright(po2->Map,&po2->dropped);
                        else
                if (key==Pldraw[po2->tag]->keyturnclockwise)
                        turnclockwise (po2->Map,&po2->dropped);
                        else
                if (key==Pldraw[po2->tag]->keyturncounterclockwise)
                        turncounterclockwise (po2->Map,&po2->dropped);
                        else
                if (key==Pldraw[po2->tag]->keynextbonus)
                        nextBonus(po2);
                        else
                if (key==Pldraw[po2->tag]->keyprevbonus)
                        previousBonus(po2);
                        else
                if (key==Pldraw[po2->tag]->keyusebonus)
                        useBonus (po2);
                        else
                if (key==Pldraw[po2->tag]->keydrop)
                        fall (po2);
                        else
                if (key==Pldraw[po->tag]->keyleft)
                        moveleft(po->Map,&po->dropped);
                        else
                if (key==Pldraw[po->tag]->keyright)
                        moveright(po->Map,&po->dropped);
                        else
                if (key==Pldraw[po->tag]->keyturnclockwise)
                        turnclockwise (po->Map,&po->dropped);
                        else
                if (key==Pldraw[po->tag]->keyturncounterclockwise)
                        turncounterclockwise (po->Map,&po->dropped);
                        else
                if (key==Pldraw[po->tag]->keynextbonus)
                        nextBonus(po);
                        else
                if (key==Pldraw[po->tag]->keyprevbonus)
                        previousBonus(po);
                        else
                if (key==Pldraw[po->tag]->keyusebonus)
                        useBonus (po);
                        else
                if (key==Pldraw[po->tag]->keydrop)
                        fall (po);
                        else
                printf ("You asked for %c (%i). Unknown!\n",key&0xFF,key&0xFF);
        }

void key2 (int key, int x, int y)
        {
        usekey (key | KEY_SPECIAL_MASK);
        }

void keyboard (unsigned char key, int x, int y)
        {
        FILE* output;
        GLint *tableau;
        #ifdef DEBUG
        printf ("You asked for %c\n",key);
        #endif
        switch (key)
                {
                case 27:
                case 'M':
                        pauseGame (po);
                        pauseGame (po2);
                        setMenu (getSystemMenu(),backmenu,display_nocleanup);
                        break;
                case 'P':
                        printf ("Exporting stencil buffer....\n");
                        output=fopen ("/root/stencil.out","w");
                        tableau=malloc (sizeof (GLint)*800*600);
                        glReadPixels (0,0,800,600,GL_STENCIL_INDEX,GL_UNSIGNED_INT,tableau);
                        fwrite (tableau,sizeof (GL_UNSIGNED_INT),800*600,output);
                        fclose (output);
                        free (tableau);
                        break;
                default :
                        usekey ( KEY_NORMAL_MASK | (int)key);
                        break;
                }
        return;
        }

void idle (void)
        {
        GLfloat eyex,eyez;
        #ifdef DEBUG
        printf ("Idle Start.\n");
        #endif

        glutPostRedisplay();
        if (po->dead && po2->dead)
                {
                StartGame (po);
                StartGame (po2);
                }
        gameidle (po);
        #ifndef SINGLE_PLAYER
        gameidle (po2);
        #endif

        return;
        }


void backmenu (int returnvalue)
        {

        free (SysMenu->menuentries[0].data);
        free (SysMenu->menuentries[1].data);
        if (isFullScreen^RequiresFullScreen)
          {
          if (RequiresFullScreen) glutFullScreen ();
          else glutReshapeWindow (800,600);
          isFullScreen=RequiresFullScreen;
          }
        glutDisplayFunc (display);
        glutReshapeFunc (reshape);
        glutKeyboardFunc (keyboard);
        glutIdleFunc (idle);
        if (returnvalue ==0xdeadbeef)
                {
                KillTextures();
                GraphicalClose ();
                exit (0);
                }
        if (po!=NULL) pauseGame (po);
        if (po2!=NULL) pauseGame (po2);
        glutPostRedisplay();
        }

int main (int argc,char **argv)
        {
        glutInit (&argc,argv);
        glutInitDisplayMode (GLUT_RGBA|GLUT_DOUBLE|GLUT_DEPTH|GLUT_STENCIL);
        glutInitWindowSize (640,480);
        glutCreateWindow ("GLtris");
        init();
        glutDisplayFunc (display);
        glutReshapeFunc (reshape);
        glutSpecialFunc (key2);
        glutKeyboardFunc (keyboard);
        glutIdleFunc (idle);
        printf ("System says stencil depth is %d.\n",glutGet (GLUT_WINDOW_STENCIL_SIZE));
        setMenu (getSystemMenu(),backmenu,NULL);
        glutMainLoop();
        return 0;
        }
